The Nature Of Complexity
「複雑さの本質」
システムの複雑さとは、システムの理解や変更を困難にするような、ソフトウェアシステムの構造に関連するあらゆるもの 具体的には以下のようなものが当てはまる
コードの一部がどのように動作するのか理解できない
ちょっとした変更でもコストが高い
変更のときにどこを修正して良いのか分からない
別のバグを発生させずにバグを修正するのが難しい
理解し修正するのが難しい = 複雑 <-> 理解し修正するのが簡単 = 単純
ただし、システムに非常に複雑な部分があっても、その部分に触れる必要がほとんどない場合、その部分はシステム全体の複雑さに影響を与えない
$ C = \sum_{p} c_p t_p
システム全体の複雑さ($ C)は、各部分 p の複雑さ($ c_p)を、それに費やす時間($ t_p)で重み付けした和で表される。
したがって、複雑さを見えない場所に隔離することは、複雑さを完全に排除することと同義である
自分だけが作業しやすいコードを作るのではなく、他の人も作業しやすいコードを書く
複雑さはがもたらす影響は、以下の3つのパターン
「変更差分の増大(Change amplification)」
一見単純に見える変更でも、多くの異なる場所でコードの修正が必要になること
タスクを完了するために、開発者がどれだけの知識を必要とするか
認知的負荷が高いと、開発者が必要な情報を習得するのに多くの時間を費やす必要がある
重要なことを見逃して、バグが発生するリスクも高くなる
認知的負荷は、モジュール間の依存関係やグローバル変数など、様々な形で発生する
より多くのコード行を必要とするアプローチの方が、認知的負荷を下げることに繋がるので、結果としてシンプルになることもある
タスクを完了するためにどのコードを修正すべきか、どんな情報を持っていないかが明らかでないこと
危険度: 「変更差分の増大」>「認知的負荷」>「未知の未知」radish-miyazaki.icon
「変更差分の増大」: 変更箇所が明確なので変更可能。
「認知的負荷」: どの情報を読めば良いか明確なので、まだ変更可能。
「未知の未知」: 最悪。システムコードの全行を読むしか無い。
高い「認知的負荷」や「未知の未知」とは真逆
複雑さの原因
あるコードが単独では理解も修正もできないこと
何らかの形で他のコードと関連しており、コードを変更する場合は、他のコードを考慮・変更する必要がある
e.g. クライアントとサーバの関係
クライアント(送信側)のコードを変更すると、サーバ(受信側)のコードも変更する必要がある
ソフトウェアの設計では、依存関係の数を減らし、残った依存関係をできるだけ単純で明白なものにすることを目標とする
「変更差分の増大」と「認知的負荷」をもたらす
e.g. 変数名があまりにも一般的すぎて、有益な情報を持っていない
e.g. 変数名に単位が明記されていない
ドキュメントが不十分なために生じる
これは設計上の問題に起因することが多い
システムが明白であれば、必要なドキュメントは小さくなる
「認知的負荷」と「未知の未知」をもたらす
「依存性」と「不明瞭さ」を取り除くことで、複雑さを軽減できる
複雑さは漸進的
小さな「依存関係」や「不明瞭さ」が複数積み重なることで引き起こされる
一度複雑さが蓄積していくと、それを取り除くのは難しい
1つ解消したところで、複雑さが解消することは無い
複数人の開発者がこれらを無視すると、複雑さは急速に増加する
hr.icon
要約
複雑さが増すと、以下の3つの問題が顕在化する
変更差分の増大
新しい機能を実装するたびに、多くのコード修正が必要になる
変更を安全に行うために必要なキャッチアップコストが高くなる
そもそも必要なキャッチアップがなにか分からない
複雑であればあるほど、既存のコードを変更するのが難しくなり、リスクも高くなる